package com.ea.report.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ea.common.SA.FaceRegService;
import com.ea.common.SA.pojo.entity.DetectPersonResult;
import com.ea.common.SA.pojo.param.PersonFaceIn;
import com.ea.common.report.pojo.vo.*;
import com.ea.common.result.BizException;
import com.ea.common.result.ErrorCode;
import com.ea.common.utils.AgeUtils;
import com.ea.report.exception.StorageException;
import com.ea.report.mapper.*;
import com.ea.report.pojo.dto.ReportDetailInfoDto;
import com.ea.report.pojo.dto.ReportPropertiesDto;
import com.ea.report.pojo.dto.UserDetailCountDto;
import com.ea.report.pojo.dto.WarningPersonDto;
import com.ea.report.pojo.po.*;
import com.ea.report.pojo.po.shenshiResult.ShenshiResultProperties;
import com.ea.report.service.*;
import feign.form.FormData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {
    @Resource
    ReportInfoMapper reportInfoMapper;
    @Resource
    ReportPropertiesMapper reportPropertiesMapper;
    @Resource
    DefaultCompanyConfMapper defaultCompanyConfMapper;
    @Resource
    UserFaceMapper userFaceMapper;
    @Resource
    UserInfoMapper userInfoMapper;
    @Resource
    private PropertiesInfoMapper propertiesMapper;
    @Resource
    StatsService statsService;
    @Resource
    SAService saService;
    @Resource
    FaceRegService faceRegService;
    @Resource
    FileService fileService;
    @Resource
    DashboardService dashboardService;


    @Override
    public UserDetailVo getUserReportVoByUserId(Long userId) {
        UserDetailCountDto userDetailCountDto = reportInfoMapper.getUserDetailCountDtoByUserId(userId);

        log.info("用户报告统计：{}", JSON.toJSONString(userDetailCountDto));
        // 获取最新报告
        LambdaQueryWrapper<ReportInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ReportInfo::getUserId, userId);
        wrapper.eq(ReportInfo::getStatus, 3);
        wrapper.orderByDesc(ReportInfo::getReceiveDate);
        wrapper.last(" limit 1");
        ReportInfo reportInfo = reportInfoMapper.selectOne(wrapper);
        log.info("用户最新报告：{}", JSON.toJSONString(reportInfo));
        if (reportInfo == null) {
            return parseUserDetailCountDtoAndReportVoToUserDetailVo(userDetailCountDto, null);
        }

        return parseUserDetailCountDtoAndReportVoToUserDetailVo(userDetailCountDto, reportInfo);
    }

    @Override
    public Long uploadVideo(String md5, Long userId, Long companyId, Integer type) {
        try {
            MultipartFile multipartFile = fileService.getMultipartFileByMd5(md5);
            // 先检测视频人脸是否存在
            // 将 multipartFile 转换成 FormData
            FormData video = new FormData(
                    "application/octet-stream",
                    multipartFile.getOriginalFilename(),
                    multipartFile.getBytes()
            );

            log.info("开始检测人脸");

            // 获得人脸的userId -> personId
            faceRegService.sim = (double) defaultCompanyConfMapper.selectById(57).getUpperValueInt() / 100;
            Long personId = faceRegService.detectPersonVideo(video).getPersonId();
            if (userId == null) {
                userId = personId;
            } else if (!userId.equals(personId)) {
                log.info("查询的为 userId: {}，实际上为personId: {}", userId, personId);
                throw new BizException(ErrorCode.TPS_FILE_UPLOAD_FACE_NO_CORRECT_ERROR);
            }

            // TODO Maxfacedetect

            log.info("请求SA");
            String uuid = saService.sendVideoToAnalyze(multipartFile, md5);
            log.info("SA成功");

            ReportInfo reportInfo = new ReportInfo();
            reportInfo.setUserId(userId);
            reportInfo.setCompanyId(companyId);
            reportInfo.setUuid(uuid);
            reportInfo.setPostDate(new Date());
            reportInfo.setStatus(0);
            reportInfo.setHasAbnormality(0);
            reportInfo.setIsDel(0);
            reportInfo.setWarningType(0);
            reportInfo.setResponseWarningCount(0);
            reportInfo.setAdaptiveWarningCount(0);
            reportInfo.setRiskWarningCount(0);
            reportInfo.setType(type);
            reportInfoMapper.insert(reportInfo);
            // System.out.println("插入成功");
            return reportInfo.getReportId();
        } catch (StorageException | BizException e) {
            throw e;
        } catch (Exception e) {
            throw new BizException(ErrorCode.TPS_SA_ERROR);
        }
    }

    @Override
    public void uploadPhoto(String md5, Long userId, String name) {
        try {
            // 上传照片，可以先用 maxFaceDetect 检测照片是否符合规格，
            // 可选用 detectPerson 与现有人脸对比相似度 然后再用 uploadFace
            // 相同的 faceId 要用 removeFace 后，才能用 uploadFace 重新上传

            MultipartFile multipartFile = fileService.getMultipartFileByMd5(md5);

            // 将 multipartFile 转换成 FormData
            FormData image = new FormData(
                    "application/octet-stream",
                    multipartFile.getOriginalFilename(),
                    multipartFile.getBytes()
            );

            faceRegService.sim = (double) defaultCompanyConfMapper.selectById(57).getUpperValueInt() / 100;
            DetectPersonResult detectPersonResult = faceRegService.maxFaceDetect(image);
            if (detectPersonResult != null && detectPersonResult.getSim() > faceRegService.sim && detectPersonResult.getPersonId() != userId) {
                //判断人员是否已经被删除
                 if(userInfoMapper.selectUserInfoByIdIsDel(detectPersonResult.getPersonId())!=1) {
                     // 人脸已经被其他人员注册的情况
                     log.info("人脸已经被其他人员注册，sim: {}, userId: {}", detectPersonResult.getSim(), detectPersonResult.getPersonId());

                     double testNum = Math.round(detectPersonResult.getSim() * 100) / 100.0;

                     LambdaQueryWrapper<UserInfo> wrapper=new LambdaQueryWrapper<>();
                     wrapper.eq(UserInfo::getUserId,detectPersonResult.getPersonId());
                     UserInfo userInfoNew=userInfoMapper.selectOne(wrapper);

                     String NameNow=userInfoNew.getName();
                     String faceMsg = "该相片人员与已注册人员: " + NameNow + " 相似度过高无法注册，相似度: "+testNum;

                     // todo 暂时去掉人脸检测，避免双胞胎情况
//                     throw new BizException(ErrorCode.TPS_FILE_UPLOAD_FACE_NO_CORRECT_ERROR, faceMsg);
                 }else{//被删除的人脸赋予isDel=1
                     userFaceMapper.deleteByFaceId(detectPersonResult.getPersonFaceId());
                 }
            }

            PersonFaceIn personFaceIn = new PersonFaceIn();
            personFaceIn.setPersonId(userId);
            personFaceIn.setImage(image);
            personFaceIn.setPersonName(name);

            // 检查UserFace是否存在
            LambdaQueryWrapper<UserFace> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserFace::getUserId, userId);
            Long faceCount = userFaceMapper.selectCount(wrapper);
            if (faceCount > 0) {
                log.info("如果已有人脸，检查是否与现有人脸是同一个人");
                // 如果已有人脸，检查是否与现有人脸是同一个人
                if (faceRegService.personFaceExist(userId, image)) {
                    // 照片已存在
                    String faceMsg="相同用户下已有人脸，请勿重复注册，用户id: "+userId;
                    // todo 暂时去掉人脸检测，避免双胞胎情况
//                    throw new BizException(ErrorCode.TPS_FILE_UPLOAD_FACE_EXIST_ERROR,faceMsg);
                }
            }

            UserFace userFace = null;
            try {
                // 直接插入新人脸信息
                userFace = new UserFace();
                userFace.setUserId(userId);
                userFace.setMd5(md5);
                userFace.setIsDel(0);
                userFaceMapper.insert(userFace);
                personFaceIn.setPersonFaceId(userFace.getUserFaceId());
                personFaceIn.setPersonId(userId);
                faceRegService.uploadFace(personFaceIn);
            } catch (Exception e) {
                // 如果更新失败，回滚人脸库
                if (userFace != null) {
                    rollBackFaceReg(userFace.getUserFaceId());
                }
            }
        } catch (BizException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
        }
    }

    private void rollBackFaceReg(Long userFaceId) {
        // 删除人脸库对应的数据
        faceRegService.removeFace(userFaceId);
    }

    @Override
    public void uploadPhotoTemp(String md5, Long userId, String name){
        try {
            // 上传照片，可以先用 maxFaceDetect 检测照片是否符合规格，
            // 可选用 detectPerson 与现有人脸对比相似度 然后再用 uploadFace
            // 相同的 faceId 要用 removeFace 后，才能用 uploadFace 重新上传
            MultipartFile multipartFile = fileService.getMultipartFileByMd5(md5);

            // 将 multipartFile 转换成 FormData
            FormData image = new FormData(
                    "application/octet-stream",
                    multipartFile.getOriginalFilename(),
                    multipartFile.getBytes()
            );

            faceRegService.sim = (double) defaultCompanyConfMapper.selectById(57).getUpperValueInt() / 100;
            DetectPersonResult detectPersonResult = faceRegService.maxFaceDetect(image);
            if (detectPersonResult != null && detectPersonResult.getSim() > faceRegService.sim && detectPersonResult.getPersonId() != userId) {
                // 人脸已经被其他人员注册的情况
                // todo 暂时去掉人脸检测，避免双胞胎情况
                log.info("人脸已经被其他人员注册，sim: {}, userId: {}", detectPersonResult.getSim(), detectPersonResult.getPersonId());
//                throw new BizException(ErrorCode.TPS_FILE_UPLOAD_FACE_NO_CORRECT_ERROR);
            }

            PersonFaceIn personFaceIn = new PersonFaceIn();
            personFaceIn.setPersonId(userId);
            personFaceIn.setImage(image);
            personFaceIn.setPersonName(name);

            // 检查UserFace是否存在
            LambdaQueryWrapper<UserFace> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserFace::getUserId, userId);
            Long faceCount = userFaceMapper.selectCount(wrapper);
            if (faceCount > 0) {
                log.info("如果已有人脸，检查是否与现有人脸是同一个人");
                // 如果已有人脸，检查是否与现有人脸是同一个人
                if (faceRegService.personFaceExist(userId, image)) {
                    // 照片已存在
                    // todo 暂时去掉人脸检测，避免双胞胎情况
//                    throw new BizException(ErrorCode.TPS_FILE_UPLOAD_FACE_EXIST_ERROR);
                }
            }

            UserFace userFace = null;
            try {
                // 直接插入新人脸信息
                userFace = new UserFace();
                userFace.setUserId(userId);
                userFace.setMd5(md5);
                userFace.setIsDel(0);
                userFaceMapper.insert(userFace);
                personFaceIn.setPersonFaceId(userFace.getUserFaceId());
                personFaceIn.setPersonId(userId);
                faceRegService.uploadFace(personFaceIn);
            } catch (Exception e) {
                // 如果更新失败，回滚人脸库
                if (userFace != null) {
                    rollBackFaceReg(userFace.getUserFaceId());
                }
            }
        } catch (BizException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
        }
    }

    @Override
    public ReportSimpleInfoListVo getReportSimpleInfoVoListByUserId(Long userId, String name, String companyName, String deptName, String positionName, List<Integer> warningTypeList, Integer page, Integer pageSize) {
        LambdaQueryWrapper<ReportInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ReportInfo::getUserId, userId);
        if (warningTypeList != null && !warningTypeList.isEmpty()) {
            wrapper.in(ReportInfo::getWarningType, warningTypeList);
        }
        wrapper.orderByDesc(ReportInfo::getPostDate);
        Page<ReportInfo> reportInfoPage = new Page<>(page, pageSize);
        Page<ReportInfo> selectedPage = reportInfoMapper.selectPage(reportInfoPage, wrapper);

        ReportSimpleInfoListVo vo = new ReportSimpleInfoListVo();
        vo.setTotal((int) selectedPage.getTotal());
        vo.setPage((int) selectedPage.getCurrent());
        vo.setPageSize((int) selectedPage.getSize());
        vo.setItems(selectedPage.getRecords().stream()
                .map(reportInfo -> parseReportToSimpleVo(name, companyName, deptName, positionName, reportInfo))
                .collect(Collectors.toList()));
        return vo;
    }

    @Override
    public ReportSimpleInfoListVo getReportList(List<Long> companyIdList, List<Long> deptIdList, List<Long> positionIdList, List<Long> userIdList, List<Integer> warningTypeList, List<Integer> statusList, String name, Date postStartDate, Date postEndDate, Date receiveStartDate, Date receiveEndDate, Date emoAnalyStartDate, Date emoAnalyEndDate, Date heartRateStartDate, Date heartRateEndDate, Integer page, Integer pageSize) {
        Page<ReportSimpleInfoVo> reportSimpleInfoVoPage = new Page<>(page, pageSize);
        Page<ReportSimpleInfoVo> simpleInfoVoPage = reportInfoMapper.getReportList(
                companyIdList,
                deptIdList,
                positionIdList,
                userIdList,
                warningTypeList,
                statusList,
                name,
                postStartDate,
                postEndDate,
                receiveStartDate,
                receiveEndDate,
                emoAnalyStartDate,
                emoAnalyEndDate,
                heartRateStartDate,
                heartRateEndDate,
                reportSimpleInfoVoPage);
        ReportSimpleInfoListVo vo = new ReportSimpleInfoListVo();
        vo.setTotal((int) simpleInfoVoPage.getTotal());
        vo.setPage((int) simpleInfoVoPage.getCurrent());
        vo.setPageSize((int) simpleInfoVoPage.getSize());
        vo.setItems(simpleInfoVoPage.getRecords());
        return vo;
    }

    @Override
    public ReportDetailInfoVo getReportDetail(Long reportId) {
        ReportInfo reportInfo = reportInfoMapper.selectById(reportId);
        if (reportInfo == null) {
            throw new BizException(ErrorCode.SYSTEM_RESOURCE_ERROR_REPORT_NOT_EXISTS);
        }
        if (reportInfo.getStatus() == 4) {
            throw new BizException(ErrorCode.SYSTEM_RESOURCE_ERROR_REPORT_SA_ERROR);
        }
        if (reportInfo.getStatus() != 3) {
            throw new BizException(ErrorCode.SYSTEM_RESOURCE_ERROR_REPORT_NOT_ANALYZED);
        }

        ReportInfoVo reportInfoVo = getReportInfoVo(reportInfo);
        ReportDetailInfoDto dto = reportInfoMapper.selectReportDetailInfoVo(reportInfo.getReportId());
        if (dto == null) {
            throw new BizException(ErrorCode.SYSTEM_RESOURCE_ERROR_REPORT_NOT_EXISTS);
        }
        ReportDetailInfoVo vo = parseReportDetailDtoToVo(dto);
        vo.setReportDetail(reportInfoVo);
        return vo;
    }

    @Override
    public String getCompanyIdByReportId(Long reportId) {
        ReportInfo reportInfo = reportInfoMapper.selectById(reportId);
        if (reportInfo == null) {
            throw new BizException(ErrorCode.SYSTEM_RESOURCE_ERROR_REPORT_NOT_EXISTS);
        }
        return reportInfo.getCompanyId().toString();
    }


    /**
     * 获得预警报告
     */
    @Override
    public GetWarningInfoVo getWarningInfoVo(List<Long> companyIdList, List<Long> deptIdList, List<Long> positionIdList, List<Long> propertiesIdList, String name, List<Integer> warningTypeList, Integer page, Integer pageSize) {
        //获取预警人数
        GetWarningInfoVo vo = reportInfoMapper.getWarningInfoDto(companyIdList, deptIdList, positionIdList, name);

        //获取人员和报告信息
        Page<WarningPersonDto> queryPage = new Page<>(page, pageSize);
        Page<WarningPersonDto> personDtpPage;
        if(propertiesIdList==null||propertiesIdList.isEmpty()){
            personDtpPage = reportInfoMapper.getWarningPersonDto(companyIdList, deptIdList, positionIdList, name, warningTypeList, null, null, queryPage);
            log.info("1");
        }else{
            personDtpPage = reportInfoMapper.getWarningPersonDtoByPropertiesId(companyIdList, deptIdList, positionIdList, propertiesIdList,name, warningTypeList, null, null, queryPage);

        }

        if (personDtpPage.getTotal() > 0) {
            //获取预警指标
            vo.setItems(parseWarningPersonDtoListToVo(personDtpPage.getRecords()));
        } else {
            vo.setItems(new ArrayList<>());
        }
        vo.setTotal((int) personDtpPage.getTotal());

        return vo;
    }

    @Override
    public StatsReportVo getStatsReport(List<Long> companyIdList, List<Long> deptIdList, Integer totalCount, String startDate, String endDate) {
        StatsReportVo vo = new StatsReportVo();
        // 当前最新预警人员数
        GetWarningInfoVo warningInfoVo;
        if (startDate == null && endDate == null) {
            warningInfoVo = reportInfoMapper.getWarningInfoDto(companyIdList, deptIdList, null, null);
            parseWarningInfoToStatsReport(vo, warningInfoVo, totalCount);
        } else {
            warningInfoVo = reportInfoMapper.getWarningInfoDtoWithDate(companyIdList, deptIdList, null, null, startDate, endDate);
            parseWarningInfoToStatsReport(vo, warningInfoVo, totalCount,
                    companyIdList, deptIdList, startDate, endDate);
        }

        vo.setStatsWarningCountTypeVo(statsService.getStatsWarningTypeVo(startDate, endDate, companyIdList, deptIdList));

        vo.setStatsWarningDeptVoList(statsService.getStatsWarningDeptVo(startDate, endDate, companyIdList, deptIdList));
        vo.setStatsWarningPropertiesVoList(statsService.getStatsWarningPropertiesVo(startDate, endDate, companyIdList, deptIdList));

        vo.setStatsGroupEmotionalMapVo(statsService.getStatsGroupEmotionalMapVo(startDate, endDate, companyIdList, deptIdList));
        vo.setStatsGroupPersonalityMapVo(statsService.getStatsGroupPersonalityMapVo(startDate, endDate, companyIdList, deptIdList));

        List<Integer> warningTypeList = new ArrayList<>();
        warningTypeList.add(1);
        warningTypeList.add(2);
        warningTypeList.add(3);
        List<WarningPersonDto> records = reportInfoMapper.getWarningPersonDto(companyIdList, deptIdList, null, null, warningTypeList, startDate, endDate, new Page<>(1, totalCount)).getRecords();
        if (!records.isEmpty()) {
            vo.setAllWarningPersonList(parseWarningPersonDtoListToVo(records));
        }
        return vo;
    }

    @Override
    public DashboardVo getDashboardVo(List<Long> companyIdList, List<Long> deptIdList,
                                      Integer totalCount,
                                      Integer totalCountFemale,
                                      Integer totalCountMale,String startDate, String endDate) {
        // DashboardVo companyId 为所有company， 其余也是
        return dashboardService.getDashboardVo(companyIdList, deptIdList, totalCount, totalCountFemale,totalCountMale,startDate, endDate);
    }

    @Override
    public GetPropertiesListVo getPropertiesList() {
        // 查询所有 properties 记录
        List<PropertiesSimpleInfoVo> propertiesList = propertiesMapper.selectAllProperties();

        // 构造返回对象
        return new GetPropertiesListVo(propertiesList);


    }

    @Override
    public void deleteUserFace(Long userId) {
        LambdaQueryWrapper<UserFace> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserFace::getUserId, userId);
        List<UserFace> userFaceList = userFaceMapper.selectList(wrapper);
        for (UserFace userFace : userFaceList) {
            faceRegService.removeFace(userFace.getUserFaceId());
        }
        userFaceMapper.delete(wrapper);
    }

    @Override
    public void updateUserInfo(Long userId, Long companyId) {
        // 更新 report info
        LambdaUpdateWrapper<ReportInfo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ReportInfo::getUserId, userId);
        updateWrapper.set(ReportInfo::getCompanyId, companyId);
        reportInfoMapper.update(null, updateWrapper);
        // 查询所有 report_info 记录
        List<ReportInfo> reportInfoList = reportInfoMapper.selectList(new LambdaQueryWrapper<>());
        if (reportInfoList.isEmpty()) {
            log.warn("未找到任何 reportInfo 记录");
            return;
        }
        // 提取 reportId
        List<Long> reportIdList = reportInfoList.stream()
                .map(ReportInfo::getReportId)
                .collect(Collectors.toList());
        // 避免 SQL 语法错误
        if (reportIdList.isEmpty()) {
            log.warn("reportIdList 为空，跳过更新 report_properties");
            return;
        }
        // 更新 report properties
        LambdaUpdateWrapper<ReportProperties> updatePropertiesWrapper = new LambdaUpdateWrapper<>();
        updatePropertiesWrapper.in(ReportProperties::getReportId, reportIdList);
        updatePropertiesWrapper.set(ReportProperties::getCompanyId, companyId);
        reportPropertiesMapper.update(null, updatePropertiesWrapper);
    }

    @Override
    public ReportDetailInfoVo getReportInfoByMd5(Long userId, String md5) {
        ReportInfo reportInfo = reportInfoMapper.selectByMd5(userId,md5);
        if (reportInfo == null) {
            throw new BizException(ErrorCode.SYSTEM_RESOURCE_ERROR_REPORT_NOT_EXISTS);
        }
        if (reportInfo.getStatus() == 4) {
            throw new BizException(ErrorCode.SYSTEM_RESOURCE_ERROR_REPORT_SA_ERROR);
        }
        if (reportInfo.getStatus() != 3) {
            throw new BizException(ErrorCode.SYSTEM_RESOURCE_ERROR_REPORT_NOT_ANALYZED);
        }

        ReportInfoVo reportInfoVo = getReportInfoVo(reportInfo);
        ReportDetailInfoDto dto = reportInfoMapper.selectReportDetailInfoVo(reportInfo.getReportId());
        if (dto == null) {
            throw new BizException(ErrorCode.SYSTEM_RESOURCE_ERROR_REPORT_NOT_EXISTS);
        }
        ReportDetailInfoVo vo = parseReportDetailDtoToVo(dto);
        vo.setReportDetail(reportInfoVo);
        return vo;
    }


    private void parseWarningInfoToStatsReport(StatsReportVo vo, GetWarningInfoVo warningInfoVo, Integer totalCount, List<Long> companyIdList, List<Long> deptIdList, String startDate, String endDate) {
        vo.setResponseWarningCount(warningInfoVo.getResponseWarningCount());
        vo.setAdaptiveWarningCount(warningInfoVo.getAdaptiveWarningCount());
        vo.setRiskWarningCount(warningInfoVo.getRiskWarningCount());
        // 查询预警人数
        Integer warningCount = reportInfoMapper.getWarningCountByDate(companyIdList, deptIdList, startDate, endDate);
        vo.setNormalCount(totalCount - warningCount);
        vo.setTotalCount(totalCount);
    }

    private void parseWarningInfoToStatsReport(StatsReportVo vo, GetWarningInfoVo warningInfoVo, Integer totalCount) {
        vo.setResponseWarningCount(warningInfoVo.getResponseWarningCount());
        vo.setAdaptiveWarningCount(warningInfoVo.getAdaptiveWarningCount());
        vo.setRiskWarningCount(warningInfoVo.getRiskWarningCount());
        // 查询预警人数
        vo.setNormalCount(totalCount
                - warningInfoVo.getResponseWarningCount()
                - warningInfoVo.getAdaptiveWarningCount()
                - warningInfoVo.getRiskWarningCount());
        vo.setTotalCount(totalCount);
    }

    private List<WarningPersonVo> parseWarningPersonDtoListToVo(List<WarningPersonDto> records) {

         List<WarningPersonVo> warningPerson=records.stream()
                .map(dto -> parseWarningPersonDtoToVo(dto))
                .collect(Collectors.toList());

         return warningPerson;
//        if(propertiesIdList==null || propertiesIdList.isEmpty()){
//            return warningPerson;
//        }
//
//        // 根据 propertiesIdList 过滤 warningPerson
//        Set<Long> propertiesIdSet = new HashSet<>(propertiesIdList);
//        List<WarningPersonVo> newWarningPerson = warningPerson.parallelStream() // 并行流
//                .filter(person -> {
//                    Set<Long> itemPropertiesIds = person.getItems().stream()
//                            .map(WarningPropertiesVo::getPropertiesId)
//                            .collect(Collectors.toSet());
//
//                    return itemPropertiesIds.containsAll(propertiesIdSet);
//                })
//                .collect(Collectors.toList());
//
//        return newWarningPerson;
    }

    private WarningPersonVo parseWarningPersonDtoToVo(WarningPersonDto dto) {
        // 查询预警指标
        List<WarningPropertiesVo> warningProperties = reportPropertiesMapper.selectWarningPropertiesVoByReportId(dto.getReportId());

        WarningPersonVo vo = new WarningPersonVo();
        vo.setItems(warningProperties);
        vo.setUserId(dto.getUserId().toString());
        vo.setReportId(dto.getReportId().toString());
        vo.setName(dto.getName());
        vo.setSex(dto.getSex());
        vo.setAge(AgeUtils.getAge(dto.getBirthday()));
        vo.setCompanyName(dto.getCompanyName());
        vo.setDepartmentName(dto.getDepartmentName());
        vo.setPositionName(dto.getPositionName());
        vo.setWarningType(dto.getWarningType());
        return vo;
    }


    private ReportDetailInfoVo parseReportDetailDtoToVo(ReportDetailInfoDto dto) {
        ReportDetailInfoVo vo = new ReportDetailInfoVo();
        vo.setReportId(dto.getReportId().toString());
        vo.setName(dto.getName());
        vo.setAge(AgeUtils.getAge(dto.getBirthday()));
        vo.setSex(dto.getSex());
        vo.setPhotoMd5(dto.getPhotoMd5());
        vo.setCompanyName(dto.getCompanyName());
        vo.setDeptName(dto.getDeptName());
        vo.setPositionName(dto.getPositionName());
        vo.setPostDate(dto.getPostDate());
        vo.setReceiveDate(dto.getReceiveDate());
        vo.setEmoAnalyDate(dto.getEmoAnalyDate());
        vo.setHeartRateDate(dto.getHeartRateDate());
        vo.setResponseWarningCount(dto.getResponseWarningCount());
        vo.setAdaptiveWarningCount(dto.getAdaptiveWarningCount());
        vo.setRiskWarningCount(dto.getRiskWarningCount());
        vo.setStatus(dto.getStatus());
        vo.setWarningType(dto.getWarningType());
        return vo;
    }

    private ReportSimpleInfoVo parseReportToSimpleVo(String name, String companyName, String deptName, String positionName, ReportInfo reportInfo) {
        ReportSimpleInfoVo vo = new ReportSimpleInfoVo();
        vo.setReportId(reportInfo.getReportId().toString());
        vo.setName(name);
        vo.setCompanyName(companyName);
        vo.setDeptName(deptName);
        vo.setPositionName(positionName);
        vo.setResponseWarningCount(reportInfo.getResponseWarningCount());
        vo.setAdaptiveWarningCount(reportInfo.getAdaptiveWarningCount());
        vo.setRiskWarningCount(reportInfo.getRiskWarningCount());
        vo.setWarningType(reportInfo.getWarningType());
        vo.setPostDate(reportInfo.getPostDate());
        vo.setReceiveDate(reportInfo.getReceiveDate());
        vo.setEmoAnalyDate(reportInfo.getVibraDate());
        vo.setHeartRateDate(reportInfo.getShenshiDate());
        vo.setStatus(reportInfo.getStatus());
        return vo;
    }

    private UserDetailVo parseUserDetailCountDtoAndReportVoToUserDetailVo(UserDetailCountDto userDetailCountDto, ReportInfo reportInfo) {
        if (userDetailCountDto == null)
            return null;

        UserDetailVo vo = new UserDetailVo();
        vo.setResponseWarningCount(userDetailCountDto.getResponseWarningCount());
        vo.setAdaptiveWarningCount(userDetailCountDto.getAdaptiveWarningCount());
        vo.setRiskWarningCount(userDetailCountDto.getRiskWarningCount());

        ReportInfoVo reportInfoVo = getReportInfoVo(reportInfo);
        vo.setLatestReportDate(reportInfo.getReceiveDate());
        vo.setLatestReportDetail(reportInfoVo);
        return vo;
    }

    private ReportInfoVo getReportInfoVo(ReportInfo reportInfo) {
        ReportInfoVo reportInfoVo = null;
        if (reportInfo != null) {
            reportInfoVo = parseReportToVo(reportInfo);
        }

        return reportInfoVo;
    }

    private ReportInfoVo parseReportToVo(ReportInfo reportInfo) {
        // 获得报告的具体数值
        List<ReportPropertiesDto> reportProperties =
                reportPropertiesMapper.selectReportPropertiesDtoByReportId(reportInfo.getReportId());

        // 处理情绪饼图四舍五入，更新 propertiesId 为 21 （负面情绪） 的值
        Integer value20 = null;
        Integer value19 = null;
        for (ReportPropertiesDto property : reportProperties) {
            if (property.getPropertiesId()!=null&&property.getPropertiesId() == 20) {
                value20 = property.getValueInt();
            } else if (property.getPropertiesId()!=null&&property.getPropertiesId() == 19) {
                value19 = property.getValueInt();
            }
        }
        for (ReportPropertiesDto property : reportProperties) {
            if (property.getPropertiesId()!=null&&property.getPropertiesId() == 21) {
                if (value20 != null && value19 != null) {
                    property.setValueInt(100 - (value20 + value19)); // 更新值
                }
                break;
            }
        }
        ReportInfoVo vo = parseReportPropertiesDtoListToVo(reportProperties);
        vo.setReportId(reportInfo.getReportId().toString());
        vo.getItems().sort(Comparator.comparingInt(ReportPropertiesVo::getIndex));

        HashMap<String, Integer> itemValue = new HashMap<>();
        for (ReportPropertiesVo item : vo.getItems()) {
            itemValue.put(item.getName(), Integer.parseInt(item.getValue()));
        }

        // 查询个人常模
        // 起始日期为一年前
        Date currentDate = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);
        calendar.add(Calendar.YEAR, -1); // 将当前日期的年份减去1
        Date lastYearDate = calendar.getTime();
        List<NormVo> personalNorm = reportInfoMapper.getPersonalNorm(reportInfo.getUserId(), lastYearDate, currentDate);
        for (NormVo normVo : personalNorm) {
            if (itemValue.containsKey(normVo.getPropertiesName())) {
                normVo.setNowValue(itemValue.get(normVo.getPropertiesName()));
            }
        }
        vo.setPersonalNorm(personalNorm);

        // 查询群体常模
        List<NormVo> groupNorm = reportInfoMapper.getGroupNorm(reportInfo.getCompanyId());
        for (NormVo normVo : groupNorm) {
            if (itemValue.containsKey(normVo.getPropertiesName())) {
                normVo.setNowValue(itemValue.get(normVo.getPropertiesName()));
            }
        }
        vo.setGroupNorm(groupNorm);
        return vo;
    }

    private ReportInfoVo parseReportPropertiesDtoListToVo(List<ReportPropertiesDto> reportPropertiesDtoList) {
        ReportInfoVo vo = new ReportInfoVo();
        List<ReportPropertiesVo> reportPropertiesVos = new ArrayList<>();
        ReportPropertiesVo BPH = null;
        ReportPropertiesVo BPL = null;
        StringBuffer comment = new StringBuffer();
        for (ReportPropertiesDto reportPropertiesDto : reportPropertiesDtoList) {
            if (reportPropertiesDto.getType() == 1) {
                ReportPropertiesVo rrvo = parseReportPropertiesToVo(reportPropertiesDto);
                if (rrvo == null) {
                    continue;
                }
                // log.info("dto:{}", reportPropertiesDto);
                if (BPH == null
                        && BPL == null
                        && reportPropertiesDto.getDefaultCompanyConfId() != null
                        && reportPropertiesDto.getDefaultCompanyConfId().equals(ShenshiResultProperties.BpH.getDefaultCompanyConfId())) {
                    BPH = new ReportPropertiesVo(rrvo);
                    BPL = new ReportPropertiesVo(rrvo);
                }
                if (BPL != null && BPL.getReferenceUpper().contains("/")
                        && reportPropertiesDto.getDefaultCompanyConfId() != null
                        && reportPropertiesDto.getDefaultCompanyConfId().equals(ShenshiResultProperties.BpH.getDefaultCompanyConfId())
                        && Integer.parseInt(BPL.getValue()) <= reportPropertiesDto.getValueInt()) {
                    rrvo.setReferenceLower(reportPropertiesDto.getReferenceLower().split("/")[0]);
                    rrvo.setReferenceUpper(reportPropertiesDto.getReferenceUpper().split("/")[0]);
                    // log.info("bpl rrvo:{}", rrvo);
                    BPL = rrvo;
                } else if (BPH != null && BPH.getReferenceUpper().contains("/")
                        && reportPropertiesDto.getDefaultCompanyConfId() != null
                        && reportPropertiesDto.getDefaultCompanyConfId().equals(ShenshiResultProperties.BpH.getDefaultCompanyConfId())
                        && Integer.parseInt(BPH.getValue()) >= reportPropertiesDto.getValueInt()) {
                    rrvo.setReferenceLower(reportPropertiesDto.getReferenceLower().split("/")[1]);
                    rrvo.setReferenceUpper(reportPropertiesDto.getReferenceUpper().split("/")[1]);
                    // log.info("bpl rrvo:{}", rrvo);
                    BPH = rrvo;
                }
                reportPropertiesVos.add(rrvo);
            } else if (reportPropertiesDto.getType() == 2 && reportPropertiesDto.getPropertiesName().equals("心理变化率")) {
                JSONObject jsonObject = JSON.parseObject(reportPropertiesDto.getValueText());
                MentalRateVo mentalRateVo = new MentalRateVo();
                mentalRateVo.setFront(JSONArray.parseArray(jsonObject.getString("front"), PointVo.class));
                mentalRateVo.setBack(JSONArray.parseArray(jsonObject.getString("back"), PointVo.class));
                vo.setMentalRateVo(mentalRateVo);

                // 计算心理变化最大值、最小值
                // 心里代谢平均值
                List<PointVo> front = new ArrayList<>(mentalRateVo.getFront());
                List<PointVo> back = new ArrayList<>(mentalRateVo.getBack());
                double min = 0d;
                double max = 0d;
                double sumX = 0d;
                int frontSize = 1;
                int backSize = 0;
                if (!front.isEmpty()) {
                    frontSize = front.size();
                    front.sort(Comparator.comparing(PointVo::getY));
                    min = front.get(0).getY();
                    max = Math.max(max, front.get(front.size() - 1).getY());
                    for (PointVo pointVo : front) {
                        if (pointVo != null && pointVo.getX() != null) {
                            sumX += pointVo.getX();
                        }
                    }
                }
                if (!back.isEmpty()) {
                    backSize = back.size();
                    back.sort(Comparator.comparing(PointVo::getY));
                    if (min == 0d) {
                        min = back.get(0).getY();
                    }
                    max = Math.max(max, back.get(back.size() - 1).getY());
                    for (PointVo pointVo : back) {
                        if (pointVo != null && pointVo.getX() != null) {
                            sumX += pointVo.getX();
                        }
                    }
                }
                double average = sumX / (frontSize + backSize);
                vo.setMentalMin(min);
                vo.setMentalMax(max);
                vo.setMentalAverage(average);
            } else if (reportPropertiesDto.getType() == 2 && reportPropertiesDto.getPropertiesName().equals("心理测试频谱图")) {
                List<PointVo> pointVos = JSONArray.parseArray(reportPropertiesDto.getValueText(), PointVo.class);
                vo.setMentalSpectrum(pointVos);
            }

            if (reportPropertiesDto.getCompare() != null && reportPropertiesDto.getCompare() != 0) {
                if (reportPropertiesDto.getCompare() == 1) {
                    comment.append(reportPropertiesDto.getPropertiesName()).append("高于参考值，意见：");
                    comment.append(reportPropertiesDto.getUpperComment()).append("；");
                } else {
                    comment.append(reportPropertiesDto.getPropertiesName()).append("低于参考值，意见：");
                    comment.append(reportPropertiesDto.getLowerComment()).append("；");
                }
            }
        }
        if (comment.length() > 0)
            vo.setComment(comment.substring(0, comment.length() - 1));
        vo.setItems(reportPropertiesVos);
        return vo;
    }

    private ReportPropertiesVo parseReportPropertiesToVo(ReportPropertiesDto reportPropertiesDto) {
        ReportPropertiesVo vo = new ReportPropertiesVo();
        vo.setReferenceLower(reportPropertiesDto.getReferenceLower());
        vo.setReferenceUpper(reportPropertiesDto.getReferenceUpper());
        vo.setName(reportPropertiesDto.getPropertiesName());
        vo.setValue(reportPropertiesDto.getValueInt().toString());
        vo.setCompare(reportPropertiesDto.getCompare());
        if (reportPropertiesDto.getDefaultCompanyConfId() != null) {
            vo.setIndex(ReportPropertiesIndex.getIndexByTitleOrDefaultId(reportPropertiesDto.getDefaultCompanyConfId().toString()).getIndex());
        } else if (reportPropertiesDto.getPropertiesName() != null) {
            vo.setIndex(ReportPropertiesIndex.getIndexByTitleOrDefaultId(reportPropertiesDto.getPropertiesName()).getIndex());
        } else {
            return null;
        }
        return vo;
    }
}
